package org.hackystat.devcathlon.event.impl;

import static org.junit.Assert.assertEquals;
import javax.xml.datatype.XMLGregorianCalendar;
import org.hackystat.devcathlon.configuration.ConfigurationManager;
import org.hackystat.devcathlon.event.Event;
import org.hackystat.devcathlon.event.EventScore;
import org.hackystat.devcathlon.match.Match;
import org.hackystat.devcathlon.team.Team;
import org.hackystat.devcathlon.test.DevcathlonTestHelper;
import org.hackystat.sensorbase.resource.projects.jaxb.Project;
import org.hackystat.utilities.tstamp.Tstamp;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * Test classes for the BestCoverage starter event. 
 *
 * @author John Ly
 *
 */

public class TestBestCoverage extends DevcathlonTestHelper {
  
  /** The amount of days for streak bonus. */
  private static int dayStreak = 5;
  /** The bonus weight for the holding highest coverage over the dayStreak. */
  private static int streakBonus = 10;
  
  private String teamName = "TestTeam";
  private String teamOwner = "TeamOwner";
  private String matchName = "TestMatch";
  private String member1 = "Member1";
  private String member2 = "Member2";
    
  /**
   * Sets up the DevcathlonConfiguration for use in these test cases. 
   * @throws Exception If problems occur setting up the configuration. 
   */
  @BeforeClass
  public static void setupConfiguration() throws Exception {
    // Set up the testing DevcathlonConfiguration for the event BestCoverage.
    String eventName = BestCoverage.eventName;
    ConfigurationManager configManager = ConfigurationManager.getInstance();
    configManager.setBaseScoreWeight(eventName, 1);
    configManager.getConfiguration(eventName);
    configManager.setWakeupInterval(eventName, 1440);
    configManager.addProperty(eventName, BestCoverage.dayStreakKey, String.valueOf(dayStreak));
    configManager.addProperty(eventName, BestCoverage.typeOfCoverageKey, "Line");
    configManager.addProperty(eventName, BestCoverage.streakBonusKey, String.valueOf(streakBonus));
  }
  
  /**
   * Tests this event when there is no sensor data for this team.
   * @throws Exception If there is a bug.
   */
  @Test
  public void testNoData() throws Exception {
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    // Now create the event instance.
    Event event = new BestCoverage();
    
    // Create a simple match containing a single team, a single project, and this event.
    Match match = addSimpleMatch(matchName, team, getProject(teamOwner, teamName), event);
    
    // Test the event with no sensor data.
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());
    
    assertEquals("Check base score 0 ", 0, score.getBaseScore());
    assertEquals("Check bonus score 0", 0, 
        score.getBonusScore(BestCoverage.streakBonusKey));
    assertEquals("Check total points 0", 0, event.computePoints(score));

    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }
  
  /**
   * Tests this event when there is a single build with coverage data.
   * @throws Exception If there is a bug.
   */
  @Test
  public void testSingleBuildCoverageSequence() throws Exception {
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    // Now create the event instance.
    Event event = new BestCoverage();
    
    // Create a simple match containing a single team, a single project, and this event.
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    
    // Send a build followed by some coverage. 
    makeCoverageData(team.getOwner(), project, Tstamp.makeTimestamp(), 50, 100);
    
    // Now compute the event
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());    
    
    assertEquals("Check base score 1", 10, score.getBaseScore());
    assertEquals("Check bonus score 1", 0, score.getBonusScore(BestCoverage.streakBonusKey));
    assertEquals("Check total points 1", 10, event.computePoints(score));
    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }
  
  /**
   * Tests this event when there is a fives builds (to earn the bonus).
   * @throws Exception If there is a bug.
   */  
  @Test
  public void testFiveBuildCoverageSequence() throws Exception {
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    // Now create the event instance.
    Event event = new BestCoverage();
    
    // Create a simple match containing a single team, a single project, and this event.
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
        
    EventScore score = null;
    XMLGregorianCalendar day = Tstamp.makeTimestamp();
    
    // Send 5 build data to obtain streak bonus 
    for (int i = 0; i < 5; i++) {    
      makeCoverageData(team.getOwner(), project, day, 50, 100);
      score = event.computeScore(match, team, day);
      day = Tstamp.incrementDays(day, 1);
    }       
    
    // Check for regular event points AND bonus
    // total = 10 standard event points + 10 bonus points
    assertEquals("Check base score 5", 10, score.getBaseScore());
    assertEquals("Check bonus score 5", 1, score.getBonusScore(BestCoverage.streakBonusKey));
    assertEquals("Check total points 5", 20, event.computePoints(score));
    
    // Check if bonus still awarded for 6th consecutive event
    makeBuildData(team.getOwner(), project, Tstamp.makeTimestamp());    
    makeCoverageData(team.getOwner(), project, Tstamp.makeTimestamp(), 50, 100);
    score = event.computeScore(match, team, Tstamp.makeTimestamp());
    // total = 10 standard event points + 10 bonus points
    assertEquals("Check base score 6", 10, score.getBaseScore());
    assertEquals("Check bonus score 6", 1, score.getBonusScore(BestCoverage.streakBonusKey));
    assertEquals("Check total points 6", 20, event.computePoints(score));
    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }
  
  /** 
   * Tests this event with two teams in match and has a single build.
   * @throws Exception If there is a bug.
   */
  @Test
  public void testTwoTeamSingleBuildSequence () throws Exception {
    String teamOwner2 = "TeamOwner2";
    Team team1 = makeTeam(teamName + "1", teamOwner, member1, member2);
    Team team2 = makeTeam(teamName + "2", teamOwner2, "Member3", "Member4");

    // Now create the event instance.
    Event event = new BestCoverage();
    
    // Create a simple match containing a two teams, a two projects, and this event.
    Project project1 = getProject(teamOwner, teamName + "1");
    Project project2 = getProject(teamOwner2, teamName + "2");
    Match match = addTwoTeamMatch(matchName, team1, team2, project1, project2, event);
    
    // Send some coverage data for team1
    makeCoverageData(team1.getOwner(), project1, Tstamp.makeTimestamp(), 50, 100);
    
    // Now compute the event
    EventScore score = event.computeScore(match, team1, Tstamp.makeTimestamp());    
    
    //Team 1 should be awarded 10 points
    assertEquals("Check team1 base score", 10, score.getBaseScore());
    assertEquals("Check team1 bonus score", 0, score.getBonusScore(BestCoverage.streakBonusKey));
    assertEquals("Check team1 total points", 10, event.computePoints(score));
    
    //Team 2 should be awarded 0 points.
    score = event.computeScore(match, team2, Tstamp.makeTimestamp());
    assertEquals("Check team2 base score", 0, score.getBaseScore());
    assertEquals("Check team2 bonus score", 0, score.getBonusScore(BestCoverage.streakBonusKey));
    assertEquals("Check team2 total points", 0, event.computePoints(score));
    
    // Cleanup.
    deleteTeam(teamName + "1");
    deleteTeam(teamName + "2");
    deleteMatch(matchName);
  }
  
  /** 
   * Tests this event with two teams in match and has a single build.
   * @throws Exception If there is a bug.
   */
  @Test
  public void testTwoTeamMultiBuildSequence () throws Exception {
    Team team1 = makeTeam(teamName + "1", teamOwner, member1, member2);
    Team team2 = makeTeam(teamName + "2", "TeamOwner2", "Member3", "Member4");

    // Now create the event instance.
    Event event = new BestCoverage();
    
    // Create a simple match containing a two teams, a two projects, and this event.
    Project project1 = getProject(teamOwner, teamName + "1");
    Project project2 = getProject("TeamOwner2", teamName + "2");
    Match match = addTwoTeamMatch(matchName, team1, team2, project1, project2, event);
    
    // Send the same coverage data for both teams.
    makeCoverageData(team1.getOwner(), project1, Tstamp.makeTimestamp(), 55, 100);   
    makeCoverageData(team2.getOwner(), project2, Tstamp.makeTimestamp(), 55, 100);
    
    // Now compute the event
    EventScore score = event.computeScore(match, team1, Tstamp.makeTimestamp());    
    
    //Team 1 should be awarded 10 points because of tie.
    assertEquals("Check team1 base score", 10, score.getBaseScore());
    assertEquals("Check team1 bonus score", 0, score.getBonusScore(BestCoverage.streakBonusKey));
    assertEquals("Check team1 total points", 10, event.computePoints(score));
    
    //Team 2 should be awarded 10 points because of tie.
    score = event.computeScore(match, team2, Tstamp.makeTimestamp());
    assertEquals("Check team2 base score", 10, score.getBaseScore());
    assertEquals("Check team2 bonus score", 0, score.getBonusScore(BestCoverage.streakBonusKey));
    assertEquals("Check team2 total points", 10, event.computePoints(score));
    
    XMLGregorianCalendar day = Tstamp.makeTimestamp();   
    // Send 5 build data to achieve 5 day streak bonus for team1.    
    for (int i = 0; i < 5; i++) {
      makeCoverageData(team1.getOwner(), project1, day, 60, 100);
      score = event.computeScore(match, team1, day);
      day = Tstamp.incrementDays(day, 1);
    }
    
    // Team 1 should be awarded 20 points.
    // 10 base points + 10 bonus points
    assertEquals("Check team1 base 5 builds", 10, score.getBaseScore());
    assertEquals("Check team1 bonus 5 builds", 1, score.getBonusScore(BestCoverage.streakBonusKey));
    assertEquals("Check team1 total points 5 blds", 20, event.computePoints(score));
    
    // Team 2 should be awarded 0 points
    score = event.computeScore(match, team2, day);
    assertEquals("Check team2 base 5 builds", 0, score.getBaseScore());
    assertEquals("Check team2 bonus 5 builds", 0, score.getBonusScore(BestCoverage.streakBonusKey));
    assertEquals("Check team2 total points 5 blds", 0, event.computePoints(score));    
   
    // Break the streak with team2 higher coverage.
    day = Tstamp.incrementDays(day, 1);
    makeCoverageData(team2.getOwner(), project2, day, 65, 100);
    
    // Team1 should have 0 points.
    score = event.computeScore(match, team1, day);
    assertEquals("Check team1 base streak end", 0, score.getBaseScore());
    assertEquals("Check team1 bonus streak end", 0, 
        score.getBonusScore(BestCoverage.streakBonusKey));
    assertEquals("Check team1 total streak end", 0, event.computePoints(score));
    
    // Team2 should have 10 points.
    score = event.computeScore(match, team2, day);
    assertEquals("Check team2 base streak end", 10, score.getBaseScore());
    assertEquals("Check team2 bonus streak end", 0, 
        score.getBonusScore(BestCoverage.streakBonusKey));
    assertEquals("Check team2 total streak end", 10, event.computePoints(score));
    
    // Fail to the attain highest coverage
    day = Tstamp.incrementDays(day, 1);
    makeCoverageData(team1.getOwner(), project1, day, 62, 100);
    
    // Team1 should have 0 points.
    score = event.computeScore(match, team1, day);
    assertEquals("Check team1 base fail", 0, score.getBaseScore());
    assertEquals("Check team1 bonus fail", 0, score.getBonusScore(BestCoverage.streakBonusKey));
    assertEquals("Check team1 total fail", 0, event.computePoints(score));
    
    // Team2 should have 10 points.
    score = event.computeScore(match, team2, day);
    assertEquals("Check team2 base fail", 10, score.getBaseScore());
    assertEquals("Check team2 bonus fail", 0, score.getBonusScore(BestCoverage.streakBonusKey));
    assertEquals("Check team2 total fail", 10, event.computePoints(score));
        
    // Cleanup.
    deleteTeam(teamName + "1");
    deleteTeam(teamName + "2");
    deleteMatch(matchName);
  }
  
  
  
  
}
